/*
    kOTF Open Trace Format - a library for generating execution traces.
    Copyright 2012 Daniel K. O.

    kOTF is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kOTF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with kOTF.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KOTF_STREAM_IMPL_H
#define KOTF_STREAM_IMPL_H

#include <fstream>

#include <kotf/Records.hpp>
#include <kotf/Events.hpp>

#include "TypesInternal.hpp"

namespace kotf {

    class Session;
    class SessionImpl;
    class Stream;
    class EventBuffer;

    class StreamImpl {
        Stream& iface;
        SessionImpl& sessionImpl;
        friend class SessionImpl;
        
        EventBuffer* eventBuffer;

        uint64_t id;
        string name;
        bool active; ///< true between start/finish calls
        size_t totalEvents;
        size_t maxEvents;

        unordered_map<string, State>   stateCache;
        unordered_map<string, Counter> counterCache;
        unordered_map<string, Channel> channelCache;

        std::filebuf file;

        const State&   findState(const string& stn);
        const Counter& findCounter(const string& cn);
        const Channel& findChannel(const string& chn);

    public:
        StreamImpl(Stream& stream, Session& sess, uint64_t id, const string& name);
        ~StreamImpl();

        uint64_t getId() const;
        const string& getName() const;
        Session& getSession();

        void write(EventBuffer* eb);

        void add(const Event& e);

        void flush(); // sends whatever events are pending to the writer
        friend class Session; // only the class Session calls this

        void setLimit(size_t limit);
        size_t getLimit() const;

        bool isActive() const;

        void start(uint64_t tag=0); ///< marks the beginning of the stream
        void start(const Stream& parent, uint64_t tag=0); ///< marks the beginning of the stream and its parent
        void finish(uint64_t tag=0); ///< marks the end of the stream

        void push(const State& st, uint64_t tag=0); ///< enters a state
        void pop(const State& st, uint64_t tag=0); ///< leaves a state
        void change(const State& oldst, const State& newst, uint64_t tag=0); ///< pops oldst and pushes newst instantly

        void push(const string& stn, uint64_t tag=0); ///< enters a state, using the state name
        void pop(const string& stn, uint64_t tag=0); ///< leaves a state, using the state name
        void change(const string& oldstn, const string& newstn, uint64_t tag=0); ///< pops oldst and pushes newst instantly, using the state names

        void update(const Counter& c, uint64_t v, uint64_t tag=0); ///< updates the counter c to the value v
        void update(const string& cn, uint64_t v, uint64_t tag=0); ///< updates the counter c to the value v, using the counter name

        void send     (const Channel& ch, uint64_t length=0, uint64_t tag=0); ///< sends a message to channel ch
        void broadcast(const Channel& ch, uint64_t length=0, uint64_t tag=0); ///< broadcasts a message to channel ch
        void recv     (const Channel& ch, uint64_t length=0, uint64_t tag=0); ///< receives a message from channel ch

        void send     (const string& chn, uint64_t length=0, uint64_t tag=0); ///< sends a message to channel ch, using the channel name
        void broadcast(const string& chn, uint64_t length=0, uint64_t tag=0); ///< broadcasts a message to channel ch, using the channel name
        void recv     (const string& chn, uint64_t length=0, uint64_t tag=0); ///< receives a message from channel ch, using the channel name


        static const char * magic;
    };

}

#endif
